#include "graphic_particle_emitter_point.h"

// .. REFERENCES

#include "primitives.h"
#include "timer.h"
#include "math.h"
#include "math_vector_3.h"
#include "graphic_particle_emitter.h"
#include "graphic_particle_table.h"

// -- PUBLIC

// .. CONSTRUCTORS

GRAPHIC_PARTICLE_EMITTER_POINT::GRAPHIC_PARTICLE_EMITTER_POINT() :
    GRAPHIC_PARTICLE_EMITTER(),
    PositionCurve(),
    PositionVariationCurve(),
    DirectionCurve(),
    DirectionAngleVariationCurve(),
    AngleCurve(),
    AngleVariationCurve(),
    SpinCurve(),
    SpinVariationCurve(),
    EmitCountCurve(),
    VelocityCurve(),
    VelocityVariationCurve(),
    LifeTimeCurve(),
    CurrentPosition( MATH_VECTOR_3::Zero ),
    CurrentPositionVariation( MATH_VECTOR_3::Zero ),
    CurrentDirection( MATH_VECTOR_3::Zero ),
    CurrentDirectionAngleVariation( 0 ),
    CurrentAngle( 0 ),
    CurrentSpin( 0 ),
    CurrentEmitCount( 0 ),
    CurrentVelocity( 0 ),
    CurrentVelocityVariation( 0 ),
    CurrentLifeTime( 0 ),
    CurrentExtent( MATH_VECTOR_2::Zero ),
    CurrentExtentVariation( MATH_VECTOR_2::Zero ),
    ParticleToEmitThreshold( 0 )
{
}

// .. OPERATIONS

VOID GRAPHIC_PARTICLE_EMITTER_POINT::Emit(
    GRAPHIC_PARTICLE_TABLE & particle_table,
    const TIMER & time_step
    )
{
    INDEX
        table_index,
        particle_index;
    COUNT
        emitted_count;

    CurrentTime += time_step.GetSecondCount();

    if( ! ItIsPaused )
    {
        CurrentPosition = PositionCurve.GetValueAtTime( CurrentTime );
        CurrentDirection = DirectionCurve.GetValueAtTime( CurrentTime );
        CurrentDirectionAngleVariation = DirectionAngleVariationCurve.GetValueAtTime( CurrentTime );
        CurrentAngle = AngleCurve.GetValueAtTime( CurrentTime );
        CurrentAngleVariation = AngleVariationCurve.GetValueAtTime( CurrentTime ) ;
        CurrentSpin = SpinCurve.GetValueAtTime( CurrentTime );
        CurrentSpinVariation = SpinVariationCurve.GetValueAtTime( CurrentTime ) ;
        CurrentEmitCount = EmitCountCurve.GetValueAtTime( CurrentTime );
        CurrentVelocity = VelocityCurve.GetValueAtTime( CurrentTime );
        CurrentVelocityVariation = VelocityVariationCurve.GetValueAtTime( CurrentTime ) ;
        CurrentLifeTime = LifeTimeCurve.GetValueAtTime( CurrentTime );
        CurrentExtent = ExtentCurve.GetValueAtTime( CurrentTime );
        CurrentExtentVariation = ExtentVariationCurve.GetValueAtTime( CurrentTime ) ;
        ParticleToEmitThreshold += Rate * time_step.GetSecondCount() * CurrentEmitCount;

        emitted_count = 0;

        if( ParticleToEmitThreshold >= 1 )
        {
        	for_each_table_index( table_index, particle_table.GetParticleTable() )
            {
                for_each_index( particle_index, GRAPHIC_PARTICLE_TABLE::FixedParticleCount )
                {
                    if ( !particle_table.GetParticleTable()[ table_index ].Enabled[ particle_index ] )
                    {
                        particle_table.GetParticleTable()[ table_index ].Enabled[ particle_index ] = true;
                        particle_table.GetParticleTable()[ table_index ].Position[ particle_index ] = CurrentPosition + ( CurrentPositionVariation * MATH_GetRandom() );
                        particle_table.GetParticleTable()[ table_index ].Velocity[ particle_index ] = GenerateRandomDirection() * ( CurrentVelocity + CurrentVelocityVariation * MATH_GetRandom() );
                        particle_table.GetParticleTable()[ table_index ].LifeTime[ particle_index ] = CurrentLifeTime;
                        particle_table.GetParticleTable()[ table_index ].Extent[ particle_index ] = CurrentExtent + ( CurrentExtentVariation * MATH_GetRandom() );
                        particle_table.GetParticleTable()[ table_index ].Angle[ particle_index ] = CurrentAngle + ( CurrentAngleVariation * MATH_GetRandom() );
                        particle_table.GetParticleTable()[ table_index ].Spin[ particle_index ] = CurrentSpin + ( CurrentSpinVariation * MATH_GetRandom() );
                        //particle_table.GetParticleTable()[ table_index ].Color[ particle_index ] = PRIMITIVE_COLOR( 1.0f, 1.0f, 1.0f, 1.0f ); //:TODO: Get the correct color

                        emitted_count++;

                        if( ParticleToEmitThreshold - emitted_count < 1 )
                        {
                            ParticleToEmitThreshold -= emitted_count;
                            return;
                        }
                    }
                }
            }
        }
    }
}

// ~~

VOID GRAPHIC_PARTICLE_EMITTER_POINT::Reset()
{
    CurrentTime = 0.0f;
    ParticleToEmitThreshold = 0;
}

// -- PRIVATE

// .. INQUIRIES

const MATH_VECTOR_3 GRAPHIC_PARTICLE_EMITTER_POINT::GenerateRandomDirection()
{
    REAL
        angle;
    MATH_VECTOR_3
        new_direction;
    REAL
        cos_rotation,
        sin_rotation;

    angle = ( MATH_GetRandom() - 0.5f ) * CurrentDirectionAngleVariation;

    cos_rotation = MATH_GetCosinus( angle );
    sin_rotation = MATH_GetSinus( angle );

    

    new_direction.X = cos_rotation * CurrentDirection.X + sin_rotation * CurrentDirection.Y ;
    new_direction.Y = -sin_rotation * CurrentDirection.X + cos_rotation * CurrentDirection.Y ;
    new_direction.Z = 0;

    return new_direction;
}
